package com.ecr.hub.service.data.histo.impl;

import java.io.File;
import java.util.Calendar;
import java.util.Date;
import java.util.List;

import javax.annotation.PostConstruct;
import javax.annotation.Resource;

import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.dao.DataAccessException;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

import com.ecr.hub.FileExcelNotSavedException;
import com.ecr.hub.database.dao.IDaoComposition;
import com.ecr.hub.database.dao.IDaoHub;
import com.ecr.hub.database.dao.IDaoInputData;
import com.ecr.hub.database.dao.IDaoSillon;
import com.ecr.hub.model.HubInputData;
import com.ecr.hub.model.sillon.Sillon;
import com.ecr.hub.service.data.histo.IDataHistorizer;
import com.ecr.hub.service.data.input.xls.IXlsDecoder;

@Component("dataHistorizer")
public class DataHistorizerImpl implements IDataHistorizer {

	// Le logger générique.
	private static final Logger log = Logger
			.getLogger(DataHistorizerImpl.class);

	@Value(value = "${history.repository.folder}")
	private String repositorySaveFolder;

	@Value(value = "${repository.folder}")
	private String repositoryFolder;

	@Value(value = "${history.offset.days}")
	private String nbOffsetDays;

	// Le dao pour les ressources de type sillon.
	@Resource(name = "daoSillon")
	private IDaoSillon daoSillon;

	// Le dao pour les ressources de type composition.
	@Resource(name = "daoComposition")
	private IDaoComposition daoComposition;

	// Le dao pour les resources concernant directement le hub.
	@Resource(name = "daoHub")
	private IDaoHub daoHub;

	// Le dao pour les ressources de type inputData.
	@Resource(name = "daoInputData")
	private IDaoInputData daoInputData;

	@PostConstruct
	public void checkSaveRepository() {

		File repSave = new File(repositorySaveFolder);
		if (!repSave.exists()) {
			repSave.mkdirs();
		}
	}

	/**
	 * Historisation de la table hub_traffic et de la table hub_input_data.
	 * Cette méthode ess lancée trois fois par jour. On attaque directement le
	 * DAO sans passer par un manager. Pas de transaction globale, chaque
	 * transaction est liée à la purge d'une seule table. On en profite pour
	 * purger les fichiers de sillon dont le statut a été traité.
	 * 
	 * Pour les fichiers, on essaye de faire au mieux, dans tous les cas, il n'y
	 * a pas de moyen simple pour faire un rollback sur des déplacements de
	 * fichier. Au pire, les fichiers ne sont pas supprimés. Les fichiers de
	 * sillon sont directement déplacés car ils ne sont pas réutilisés dans
	 * l'application. Les fichiers de composition sont traités lors de la
	 * suppression du sillon.
	 */

	@Override
	public void historizeTrafficData() {

		log.info("Purge table hub_traffic....");

		// Purge traffic.
		try {
			int nbRecords = daoHub.historizeTraffic();
			log.info("Nb enregistrements traités : " + nbRecords);
			log.info("Purge hub_traffic OK");
		} catch (DataAccessException e) {
			log.warn("Purge hub_traffic KO : " + e.getMessage());
		} catch (Exception e) {
			log.warn("Purge hub_traffic KO : " + e.getMessage());
		}

		log.info("Purge table hub_input_data....");

		// Purge input_data.
		try {
			int sillonFiles = 0;
			int badSillonFiles = 0;
			List<HubInputData> lstInputData = daoInputData.historize();
			// Déplacement des fichiers.
			for (HubInputData hubInputData : lstInputData) {
				// Si concerne fichier de sillon, on déplace le fichier.
				if (hubInputData.getFileStoreName().indexOf(
						IXlsDecoder.FILE_PREFIX_SILLONS) != -1) {
					try {
						historizeFile(hubInputData.getFileStoreName());
						sillonFiles++;
					} catch (FileExcelNotSavedException e) {
						log.warn("hub_input_data : " + e.getMessage());
						badSillonFiles++;
					}
				}
			}
			log.info("Nb enregistrements traités : " + lstInputData.size());
			log.info("Nb fichiers sillons déplacés : " + sillonFiles);
			log.info("Nb fichiers sillons non déplacés : " + badSillonFiles);
			log.info("Purge hub_input_data : "
					+ ((badSillonFiles == 0) ? " OK " : " KO "));

		} catch (DataAccessException e) {
			log.warn("Purge hub_input_data KO : " + e.getMessage());
		} catch (Exception e) {
			log.fatal("Purge hub_input_data KO : " + e.getMessage());
		}
	}

	/**
	 * Historisation des tables hub_sillon et hub_compo. On supprime tous les
	 * enregistrements qui sont supérieurs à trois semaines.
	 * 
	 * On supprime les fichiers de composition à ce moment, en effet, on peut
	 * avoir un statut "Close" dans la table hub_input_data mais le sillon n'est
	 * pas encore traité, or à partir du sillon on a un lien sur le fichier de
	 * composition. Comme l'utilisateur veut conserver un historique de trois
	 * semaines pour le planing, on est obligé de conserver ces fichiers.
	 */
	@Override
	@Transactional
	public void historizeSillonData() {

		log.info("Purge table hub_sillon...");

		try {
			int compoFiles = 0;
			int badCompoFiles = 0;

			// Récupération de la date du jour.
			Calendar cal = Calendar.getInstance();
			cal.setTime(new Date());
			// Soutraction du nombre de jours.
			// TODO : Remplacer le + par - pour la purge.
			cal.add(Calendar.DATE, +Integer.parseInt(nbOffsetDays));

			List<Sillon> lstSillons = daoSillon.historize(cal.getTime());

			// On boucle sur les sillons pour historiser les compositions.
			for (Sillon sillon : lstSillons) {
				// On déplace les compositions.
				daoComposition.historize(sillon.getId());
				// On déplace les fichiers (ici rien à faire en cas d'erreur.)
				try {
					historizeFile(sillon.getCompositionFileName());
					compoFiles++;
				} catch (FileExcelNotSavedException e) {
					log.warn("Purge hub_sillon : " + e.getMessage());
					badCompoFiles++;
				}
			}
			log.info("Nb enregistrements traités : " + lstSillons.size());
			log.info("Nb fichiers composition déplacés : " + compoFiles);
			log.info("Nb fichiers composition non déplacés : " + badCompoFiles);
			log.info("Purge hub_sillon : "
					+ ((badCompoFiles == 0) ? " OK " : " KO "));

		} catch (DataAccessException e) {
			log.warn("Purge hub_sillon KO : " + e.getMessage());
		} catch (Exception e) {
			log.fatal("Purge hub_sillon KO : " + e.getMessage());
		}
	}

	/**
	 * Déplacement d'un fichier du répertoire de travail vers un répertoire de
	 * sauvegarde. Le problème est que File ne soulève aucune exception....
	 */
	private void historizeFile(String fileName)
			throws FileExcelNotSavedException {

		String filePath = repositoryFolder + fileName;
		String fileSavePath = repositorySaveFolder + fileName;
		File source = new File(filePath);
		if (source.exists()) {
			File save = new File(fileSavePath);
			source.renameTo(save);

			if (!save.exists())
				throw new FileExcelNotSavedException(
						"Impossible de sauvegarder le fichier : " + fileName);
		}
	}
}
